package com.test.es;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.elasticsearch.action.get.GetRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.Before;
import org.junit.Test;


public class JavaESQuery {

	private TransportClient client;
	
	@Before
	public void before()throws Exception{
		Settings settings = Settings.builder().put("cluster.name", "my-5i5j").build();
		client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(new InetSocketAddress("10.1.66.76", 9300)));
	}
	
	/**
	 * 插入
	 * @throws IOException
	 */
	@Test
	public void testInsert() throws IOException{
		client.prepareIndex("twitter", "tweet", "3").setSource(XContentFactory.jsonBuilder()
				.startObject().field("user", "guanyuliang").field("postDate", new Date()).field("message", "hello").endObject()).get();
	}
	
	/**
	 * 使用get查询
	 * @throws Exception
	 */
	@Test
	public void testGet()throws Exception{
		GetRequestBuilder requestBuilder = client.prepareGet("twitter", "tweet", "1");
		GetResponse response = requestBuilder.get();
		System.out.println(response.getSourceAsString());
	}
	
	/**
     * 使用QueryBuilder
     * termQuery("key", obj) 完全匹配
     * termsQuery("key", obj1, obj2..)   一次匹配多个值
     * matchQuery("key", Obj) 单个匹配, field不支持通配符, 前缀具高级特性
     * multiMatchQuery("text", "field1", "field2"..);  匹配多个字段, field有通配符忒行
     * matchAllQuery();         匹配所有文件
     */
	@Test
	public void testQuery()throws Exception{
		//termQuery("key", obj)完全匹配
		/*
		QueryBuilder queryBuilder = QueryBuilders.termQuery("user", "guanyu");
		searchFunction("twitter", queryBuilder);
		*/
		//QueryBuilder queryBuilder = QueryBuilders.termsQuery("employer.keyword",  "Enaut","Quiltigen");
		//QueryBuilder queryBuilder = QueryBuilders.termsQuery("employer.keyword", new ArrayList<String>().add("Enaut"));
		//QueryBuilder queryBuilder = QueryBuilders.matchQuery("city.keyword", "Wright");
		QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("lastname.keyword", "Rice", "gender.keyword", "M");
		//QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
		searchFunction("bank", queryBuilder);
	}
	
	 /**
     * 组合查询
     * must(QueryBuilders) :   AND
     * mustNot(QueryBuilders): NOT
     * should:                  : OR
     */
	@Test
	public void testQuery2()throws Exception{
		QueryBuilder queryBuilder = QueryBuilders.boolQuery()
				.mustNot(QueryBuilders.termQuery("gender.keyword", "F"))
				.must(QueryBuilders.termQuery("age", 30))
				.should(QueryBuilders.termQuery("employer.keyword", "Quantasis"));
		searchFunction("bank", queryBuilder);
	}
	
	/**
	 * 只查询一个Id的
	 * @throws Exception
	 */
	@Test
	public void testIdsQuery()throws Exception{
		QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("1");
		searchFunction("twitter", queryBuilder);
	}
	
	 /**
     * 包裹查询, 高于设定分数, 不计算相关性
     */
	@Test
	public void testConstantScoreQuery()throws Exception{
		QueryBuilder queryBuilder = QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("lastname.keyword", "Rice").boost(2.0f));
		searchFunction("bank", queryBuilder);
	}
	
	/**
	 * 模糊查询
	 * 不能用通配符
	 * @throws Exception
	 */
	@Test
	public void testFuzzyQuery()throws Exception{
		QueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("lastname.keyword", "ice");
		searchFunction("bank", queryBuilder);
	}
	
	/**
	 * 前缀查询
	 */
	@Test
	public void testPrefixQuery(){
		QueryBuilder queryBuilder = QueryBuilders.prefixQuery("user", "guanyu");
		searchFunction("twitter", queryBuilder);
	}
	
	/**
	 * 查询解析查询字符串
	 */
	@Test
	public void testQueryString(){
		QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("+guanyu");
		searchFunction("twitter", queryBuilder);
	}
	
	/**
	 * 范围查询
	 */
	@Test
	public void testRangeQuery()throws Exception{
		/*
		QueryBuilder queryBuilder = QueryBuilders.rangeQuery("balance")
				.from(10000)
				.to(15000)
				.includeLower(true) //包含上界
				.includeUpper(true); //包含下界
		searchFunction("bank", queryBuilder);
		*/
		
		//日期范围查询
		long startTime = dateToLong(stringToDate("2017-12-15 09:00:00","yyyy-MM-dd HH:mm:ss"));
		long endTime = dateToLong(stringToDate("2017-12-15 22:00:00","yyyy-MM-dd HH:mm:ss"));
		QueryBuilder queryBuilder = QueryBuilders.rangeQuery("postDate")
				.from(startTime)
				.to(endTime);
		searchFunction("twitter", queryBuilder);
	}
	
	//字符串转日期
	public Date stringToDate(String strTime, String formatType) throws Exception{
		SimpleDateFormat sdf = new SimpleDateFormat(formatType);
		Date date = sdf.parse(strTime);
		return date;
	}
	
	//日期转long
	public Long dateToLong(Date date){
		Long dateLong = date.getTime();
		return dateLong;
	}
	
	/**
	 * 跨度查询
	 */
	@Test
	public void testSpanQueries(){
		QueryBuilder queryBuilder = QueryBuilders.spanFirstQuery(QueryBuilders.spanTermQuery("user", "guanyu"),30000); // Max查询范围的结束位置  
		
        // Span Term  
         QueryBuilder queryBuilder5 = QueryBuilders.spanTermQuery("user", "guanyu");  
         
		searchFunction("twitter", queryBuilder5);
	}
	
	/**
     * 通配符查询, 支持 * 
     * 匹配任何字符序列, 包括空
     * 避免* 开始, 会检索大量内容造成效率缓慢
     */
	@Test
	public void testWildCardQuery(){
		QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("user", "guanyu*");
		searchFunction("twitter", queryBuilder);
	}
	
	/**
     * 对结果设置高亮显示
     */
	@Test
    public void testHighLighted() {
        /*  5.0 版本后的高亮设置
         * client.#().#().highlighter(hBuilder).execute().actionGet();
        HighlightBuilder hBuilder = new HighlightBuilder();
        hBuilder.preTags("<h2>");
        hBuilder.postTags("</h2>");
        hBuilder.field("user");        // 设置高亮显示的字段
        */
    	HighlightBuilder highlightBuilder = new HighlightBuilder();
    	highlightBuilder.preTags("<h1>");
    	highlightBuilder.postTags("</h1>");
    	highlightBuilder.field("lastname");
        // 加入查询中
        SearchResponse response = client.prepareSearch("bank")
            .setQuery(QueryBuilders.matchQuery("lastname", "Ayala"))
            .highlighter(highlightBuilder)
            .execute().actionGet();
        
        // 遍历结果, 获取高亮片段
        SearchHits searchHits = response.getHits();
        System.out.println("共搜到:"+searchHits.getTotalHits()+"条结果!");
        for(SearchHit hit:searchHits){
            System.out.println("String方式打印文档搜索内容:");
            System.out.println(hit.getSourceAsString());
            System.out.println("Map方式打印高亮内容");
            System.out.println(hit.getHighlightFields());

            System.out.println("遍历高亮集合，打印高亮片段:");
            Text[] text = hit.getHighlightFields().get("lastname").getFragments();
            for (Text str : text) {
                System.out.println(str.string());
            }
        }
    }
    
    /**
     * 对response结果的分析
     * @param response
     */
    private void testResponse(SearchResponse response) {
        // 命中的记录数
        long totalHits = response.getHits().totalHits();
        System.out.println("totalHits = " + totalHits);
        for (SearchHit searchHit : response.getHits()) {
            // 打分
            float score = searchHit.getScore();
            // 文章id
            int id = Integer.parseInt(searchHit.getSource().get("id").toString());
            // title
            String title = searchHit.getSource().get("title").toString();
            // 内容
            String content = searchHit.getSource().get("content").toString();
            // 文章更新时间
            long updatetime = Long.parseLong(searchHit.getSource().get("updatetime").toString());
        }
    }
    
	//打印数据
	private void searchFunction(String index, QueryBuilder queryBuilder) {
        SearchResponse response = client.prepareSearch(index)
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(queryBuilder)
                .setSize(10).get();
        for (SearchHit hit : response.getHits()) {
        	System.out.println(hit.getSourceAsString());
        }
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
